﻿
using HBase.task.Equpt;
using Net.http;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace HBase {
    public abstract class ZtTask :ITask {
        public static int maxSleepTime= 120000;
        public String p;
        public int cpuId=-1;
        public TaskStat getStat() {
            return stat;
        }
        public int cNo=0;

        public readonly TaskStat stat = new TaskStat();
        public String className;

        private Task jobTask;
        protected int time = 100;
        protected bool exceptionSleep = true;
        protected int oneTimeSleep = 0;
        private int extralSleep = 2000;
       
        public bool runed = false;
        public ZtTask() {
            className = this.GetType().Name;
            stat.className = className;
            for (int i=1;i< className.Length;i++) {
                String index = className.Substring(i);
                if (int.TryParse(index, out cNo)) {
                    return;
                }
            }

        }

      public  int getCNo() {

            return cNo;
        
        }

        protected virtual bool init() {
            return true;
        }
        public void start() {
            try {
                if( runed ) {
                    console(InfoCode.consle_ztTask_runed,"已经启动");
                }
                if( !init() ) {
                    console(InfoCode.consle_ztTask_init, "初始化异常");
                    return;
                }
                runed = false;
                jobTask = Task.Factory.StartNew(() => { doAction(); } ,TaskCreationOptions.LongRunning);
               


            } catch( Exception e ) {

                LoggerCommon.startError(InfoCode.start_task,className + "初始化异常" ,e);
            }
        }

        bool depend() {
            Type t11 = this.GetType();
            FieldInfo[] pps =  t11.GetFields(BindingFlags.Public  | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo pp in pps) {
                Type t = pp.FieldType;
                if (!t.IsClass) {
                    continue;
                }
                if (t.IsSubclassOf(typeof(ZtTask))) {
                    object value = pp.GetValue(this);
                    ITask d = value as ITask;
                    if (d == null) {
                        d = (ZtTask)TaskPool.get(t.Name);
                        pp.SetValue(this, d);
                        consoleOnly(InfoCode.consleOnly_auto_Dependency_Injection, className + "自动注入"+t.Name);
                    }
                    if (d != null) {
                        if (!d.isRuned()) {
                            consoleOnly(InfoCode.consleOnly_runing, d.getStat().className + "待启动");
                            return false;
                        }
                    }



                }

            }
            return true;

        }
     
        protected virtual bool onlyOneTimeAsync() {
            return true;
        }
        protected virtual long oneMaxTime() {
            return 2000 + time + oneTimeSleep;
        }

        protected virtual bool HaRun() {
            return BaseConfig.Working;
        }
        [DllImport("kernel32.dll")]
        static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);

        //Get the handler of current thread
        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentThread();
        static ulong SetCpuID(int lpIdx) {
            ulong cpuLogicalProcessorId = 0;
            if (lpIdx < 0 || lpIdx >= System.Environment.ProcessorCount) {
                lpIdx = 0;
            }
            cpuLogicalProcessorId |= 1UL << lpIdx;
            return cpuLogicalProcessorId;
        }

        protected virtual void doException(Exception ex)
        {
             
        }

        private void doAction() {
            if (cpuId > -1) {
                try {
                    ulong LpId = SetCpuID((int)cpuId);
                    SetThreadAffinityMask(GetCurrentThread(), new UIntPtr(LpId));
                } catch (Exception e){
                    consoleOnly(InfoCode.consleOnly_main_win_cpu, "设置cpu异常"+e.Message);
                }
            
            }
         
            do {
                try {
                

                    if (!HaRun()) {
                        runed = false;
                        consoleOnly(InfoCode.consleOnly_main_start,"主程序已启动");
                        Thread.Sleep(200);
                        continue;
                    }
                    bool res = work();
                    Thread.Sleep(time + oneTimeSleep);
                    oneTimeSleep = 0;
                    if( res ) {
                        extralSleep = 2000;
                    } else {
                        fileAll(InfoCode.fileAll_ztTask_extra_time, "延期执行{0}s" ,extralSleep / 1000);
                        exceptionSleeps();
                    }

                } catch( Exception ex ) {
                    doException(ex);
                    String show = string.Format("{0} sleep {1}s :{2}" ,className ,extralSleep / 1000 ,ex.Message);
                    LoggerCommon.error(InfoCode.error_ztTask_exception, show, ex);
                    exceptionSleeps();
                }
            } while( true );
        }
        /// <summary>
        ///
        /// </summary>
        public bool work() {
            lock( stat ) {
                bool res = false;
                if( !runed ) {
                    runed = onlyOneTimeAsync()&& depend();
                }
                if (!runed) {
                    return true;
                }
               
                stat.time = this.time;
                long beginTime = DateTime.Now.Ticks;
           
                res = excute();
              
                afterExcute();
                analysis(beginTime);
                return res;
            }
        }
        public virtual void afterExcute() { }
        void analysis(long beginTime) {
            var n = DateTime.Now;
            long lastTime = (n.Ticks - beginTime);
            long d = beginTime - HUtil.randSeek;
            d = d > 0 ? d >> 40 : 0;
            stat.worklastTime = lastTime;
            if( lastTime > oneMaxTime()*10000 ) {
                fileAll(InfoCode.fileAll_ztTask_run_long_time,"线程执行时间过长" + lastTime);
            }
            stat.workAllTime += lastTime;
            stat.workCount++;
            if( lastTime > stat.maxTime ) {
                stat.maxTime = lastTime;
            }
            if( lastTime < stat.minTime || stat.minTime == 0 ) {
                stat.minTime = lastTime;
            }
            oneTimeSleep = oneTimeSleep == 0 ? ( int ) d : oneTimeSleep;

        }
        protected void exceptionSleeps() {
            stat.exceptionCount++;
            Thread.Sleep(extralSleep);
            extralSleep *= 2;
            if( extralSleep > maxSleepTime) {
                extralSleep = maxSleepTime;
            }
        }
        abstract public bool excute();
      
        String formatStr(String format, params object[] p) {
            if (String.IsNullOrWhiteSpace(format)) {
                return "";
            }
            if (p.Length > 0) {
                String[] pp = new string[p.Length];
                for (int i = 0; i < pp.Length; i++) {
                    pp[i] = "[" + p[i].ToString() + "]";
                }
                format = String.Format(format, p);
            }
            return stat.className + "->" + format;
        }

        public void fileAll(int code,String format, params object[] p) {
        
            LoggerCommon.fileAll(code, formatStr(format, p));
        }

        public void console(int code,String format ,params object[] p) {
       
            LoggerCommon.consol(code, formatStr(format, p));
        }
        public void consoleOnly(int code,String format ,params object[] p) {

           
           
            LoggerCommon.consoleOnly(code,formatStr( format, p));
        }
       public void consoleOnly2<T>(int code,String format , T[] p) {
            String key="";
            for (int i = 0;i < p.Length;i++) {  
                key+=p[i].ToString();
            }
            LoggerCommon.consoleOnly(code,formatStr( format, p));
        }
        public bool isRuned() {
            return runed;
        }
    }
}
